<?php

/**
 * Phrappe_Helper_Array provides a set of arrays that ease working with
 * arrays.
 *
 * Phrappe_Helper_Array implements the Singleton pattern, so only one instance
 * will ever exist.   Helper functions are likely static.
 *
 * @copyright   Copyright (c) 2006, John D Wells Jr
 * @author      John D Wells Jr <mailto:wellsdjohn@gmail.com>
 * @category    Phrappe
 * @package     Phrappe_Helper
 * @uses        Zend_Exception
 */

/**
 * @copyright   Copyright (c) 2006, John D Wells Jr
 * @author      John D Wells Jr <mailto:wellsdjohn@gmail.com>
 * @category    Phrappe
 * @package     Phrappe_Helper
 * @uses        Zend_Exception
 */
class Phrappe_Helper_Array
{
    /**
     * Instance of Phrappe_Helper_Array
     * @var Phrappe_Helper_Array
     */
    static private $_instance = null;

    /**
     * Singleton pattern
     */
    private function __construct() {}

    /**
     * Singleton pattern
     */
    private function __clone()
    {}

    /**
     * Return one and only one instance of the Phrappe_Helper_Array object
     *
     * @return Phrappe_Helper_Array
     */
    static public function getInstance()
    {
        if (!self::$_instance instanceof self) {
           self::$_instance = new self();
        }

        return self::$_instance;
    }

    /**
     * Sorts an array on multiple columns.  Array is passed by reference,
     * so array becomes permanently sorted.
     *
     * First parameter is the array to be sorted.
     *
     * Second parameter is an associative array of columns to sort.
     * Keys are column names/index values, and values are the
     * sort order ('ASC' or 'DESC').
     *
     * If an empty array is passed as the second parameter, the method sorts
     * by the first column, in ASCending order.
     *
     * @param   Array   &$array
     * @param   Array   $columns
     */
    static public function sort_multi(&$array, $columns = array())
    {
        switch('handleif')
        {
            case(! is_array($array)):
                $msg = 'First parameter must be of type Array.';
                throw new Zend_Exception($msg);
            
            case(! is_array($columns)):
                $msg = 'Second parameter must be of type Array.';
                throw new Zend_Exception($msg);

            case(count($columns) == 0):
                foreach($array[0] as $key => $value)
                {
                    $columns = array($key => 'ASC');
                    break 2;
                }
        }
        
        // Set $columns as a property of Phrappe_Helper_Array so that
        // Phrappe_Helper_Array::_sort_multi_compare() can get access to it.
        self::getInstance()->sort_multi_columns = $columns;
        
        // Perform custom sort
        usort($array, array(self::getInstance(), '_sort_multi_compare'));
        
        // Unset Phrappe_Helper_Array::sort_multi_columns
        unset(self::getInstance()->sort_multi_columns);
    }

    /**
     * The multi-array comparison function.  Requires a
     * Phrappe_Helper_Array::sort_multi_array to be set with an associative
     * array of columns to sort with.
     *
     * @param   Array   $array1     First array to compare.
     * @param   Array   $array2     Second array to compare.
     * @return  Integer                 0, -1, 1
     */
    protected function _sort_multi_compare($array1, $array2)
    {
        $dirArray = array('asc' => array('lessThan' => -1, 'greaterThan' => 1),
                           'desc' => array('lessThan' => 1, 'greaterThan' => -1));

        switch('errorif')
        {
            // Make sure that the columns we're asking to sort by exist.
            case(
                 count(array_intersect(array_keys($array1),
                                 array_keys($this->sort_multi_columns)))
                 < count($this->sort_multi_columns)
                 ):
                $msg = '1 or more column values were not found in the array.';
                throw new Zend_Exception($msg);
        }

        // call each sorting method in turn
        foreach($this->sort_multi_columns as $column => $direction)
        {
            if ($array1[$column] < $array2[$column]) {
                return $dirArray[strtolower($direction)]['lessThan'];
            } else if ($array1[$column] > $array2[$column]) {
                return $dirArray[strtolower($direction)]['greaterThan'];
            }
        }
        
        // arrays were equal!
        return 0;
    }
}
